package com.open.generate.dispatch;

import com.open.generate.database.MysqlSelectProperty;
import com.open.generate.model.ColumnData;
import com.open.base.model.CodeGenerate;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author dashu
 * @date 2025/1/19 21:36
 * @description 数据库属性获取
 */
@Component
public class FactoryTemplateDispatch {

    @Autowired
    private MysqlSelectProperty dataBaseAttribute;

    /**
     * 获取所有列名字或属性名
     *
     * @param type 类型 ：取表列名还是对应的属性名 1-列名 0-属性名
     * @return
     * @throws SQLException
     */
    public String combineColumn(List<ColumnData> columns, int type,
                                Map<String, ColumnData> peKey) {
        StringBuilder commonColumns = new StringBuilder();
        int count = 0;
        for (ColumnData colum : columns) {
            if (!(peKey.containsKey(colum.getColumnName()) && peKey.get(colum.getColumnName()).getAuto())) {
                if (count > 0) {
                    commonColumns.append("|");
                }
                commonColumns.append(type == 1 ? colum.getColumnName() : colum.getPropertyName());
                count++;
            }
        }
        return commonColumns.toString();
    }

    public ColumnData queryPk(CodeGenerate codeGenerate) throws SQLException {
        ColumnData item = null;
        Map<String, ColumnData> peKey = dataBaseAttribute.queryTablePeKey(codeGenerate.getTableName(), codeGenerate.getDatabase());
        if (!peKey.isEmpty()) {
            Map.Entry<String, ColumnData> entry = peKey.entrySet().iterator().next();
            item = entry.getValue();
        }
        return item;
    }

    public String combineFields(CodeGenerate codeGenerate) throws SQLException {
        List<ColumnData> dataList = dataBaseAttribute.queryColumnDatas(codeGenerate.getDatabase(), codeGenerate.getTableName());
        StringBuilder str = new StringBuilder();
        StringBuilder getset = new StringBuilder();
        for (ColumnData d : dataList) {
            str.append("\r    /**").append(StringUtils.trimToEmpty(d.getColumnComment())).append("*/");
            str.append("\r    ").append("private ").append(d.getJdbcType()).append(" ").append(d.getPropertyName()).append(";");
            String maxChar = d.getPropertyName().substring(0, 1).toUpperCase();
            String method = maxChar + d.getPropertyName().substring(1);
            getset.append("\r    ").append("public ").append(d.getJdbcType()).append(" ").append("get").append(method).append("() {\r    ");
            getset.append("    return this.").append(d.getPropertyName()).append(";\r    }");
            getset.append("\r    ").append("public void ").append("set").append(method).append("(").append(d.getJdbcType()).append(" ").append(d.getPropertyName()).append(") {\r    ");
            getset.append("    this.").append(d.getPropertyName()).append("=").append(d.getPropertyName()).append(";\r    }");
            getset.append("\n");
        }
        String toString = "\r    @Override" +
                "\r    " + "public String toString() {" +
                "\r        return " + combineMsg(dataList) + ";" +
                "\r    }";
        return str + "\r" + getset + "\r" + toString;
    }

    private String combineMsg(List<ColumnData> dataList) {
        StringBuilder msg = new StringBuilder("\"{");
        int count = 0;
        for (ColumnData columnData : dataList) {
            if (count > 0) {
                msg.append(",");
            }
            msg.append("\\").append("\"").append(columnData.getPropertyName()).append("\\").append("\"").append(":");
            if ("String".equals(columnData.getJdbcType())) {
                msg.append("\\").append("\"").append("\"").append("+").append("this.")
                        .append(columnData.getPropertyName()).append("+").append("\"").append("\\").append("\"");
            } else if ("java.util.Date".equals(columnData.getJdbcType())) {
                msg.append("\\").append("\"").append("\"").append("+").append("this.")
                        .append(columnData.getPropertyName()).append("+").append("\"").append("\\").append("\"");
            } else {
                msg.append("\"").append("+").append("this.").append(columnData.getPropertyName()).append("+")
                        .append("\"");
            }
            count++;
        }
        msg.append("}\"");
        return msg.toString();
    }

    public List<ColumnData> columnData(CodeGenerate codeGenerate) throws SQLException {
        return dataBaseAttribute.queryColumnDatas(codeGenerate.getDatabase(), codeGenerate.getTableName());
    }

    public Map<String, String> createSql(CodeGenerate codeGenerate) throws SQLException {
        String databaseName = codeGenerate.getDatabase();
        String tableName = codeGenerate.getTableName();
        Map<String, ColumnData> peKey = dataBaseAttribute.queryTablePeKey(tableName, databaseName);
        if (peKey.isEmpty()) {
            throw new SQLException("No primary key was set");
        }
        List<ColumnData> dataList = dataBaseAttribute.queryColumnDatas(databaseName, tableName);
        String insert = insert(tableName, dataList, peKey);
//		String[] columnList = columnAll(dataList); // 表所有字段
        String columnFields = columnFields(dataList); // 表所有字段 按","隔开
        String update = update(tableName, dataList, peKey);
        String selectById = selectByPk(tableName, peKey);
        String byPk = findByPk(tableName, peKey);
        String delete = delete(tableName, peKey);
        String remove = remove(tableName, peKey);
        String batchSave = batchSave(tableName, dataList, peKey);
        String batchUpdate = batchUpdate(tableName, dataList, peKey);
        Map<String, String> sqlMap = new HashMap<String, String>();
        Map.Entry<String, ColumnData> entry = peKey.entrySet().iterator().next();
        String json = combineMsg(dataList);
        sqlMap.put("json", json);
        sqlMap.put("pey", entry.getKey());
        sqlMap.put("columnFields", columnFields);//数据库列
        sqlMap.put("insert", insert);
        sqlMap.put("update", update);
        sqlMap.put("batchSave", batchSave);
        sqlMap.put("batchUpdate", batchUpdate);
        sqlMap.put("delete", delete);
        sqlMap.put("remove", remove);
        sqlMap.put("selectById", selectById);
        sqlMap.put("findByPk", byPk);
        return sqlMap;
    }

    /**
     * 获取所有列属性名
     *
     * @param columns
     * @return String
     * @throws
     */
    private String columnFields(List<ColumnData> columns) {
        StringBuilder columnFields = new StringBuilder();
        int i = 0;
        for (ColumnData column : columns) {
            if (i > 0) {
                columnFields.append(",");
            }
            columnFields.append(column.getColumnName());
            i++;
        }
        return columnFields.toString();
    }

    /**
     * 修改记录(全量修改)
     */
    /*public String update(String tableName, List<ColumnData> columns, Map<String, ColumnData> peKey) {
        StringBuilder items = new StringBuilder();
        int i = 0;
        for (ColumnData data : columns) {
            if (!peKey.containsKey(data.getColumnName())) {
                if (i > 0) {
                    items.append(",");
                }
                items.append(data.getColumnName()).append("=#{").append(data.getPropertyName()).append("}");
                i++;
            }
        }
        Map.Entry<String, ColumnData> entry = peKey.entrySet().iterator().next();
        return "update " + tableName + " set " + items + " where " + entry.getKey() + "=#{"
                + entry.getValue().getPropertyName() + "}";
    }*/

    private String delete(String tableName, Map<String, ColumnData> peKey) {
        StringBuilder sb = new StringBuilder();
        sb.append("delete");
        sb.append("\t from ").append(tableName).append(" where ");
        Map.Entry<String, ColumnData> entry = peKey.entrySet().iterator().next();
        sb.append(entry.getKey()).append(" = #{").append("pk").append("}");
        return sb.toString();
    }

    private String remove(String tableName, Map<String, ColumnData> peKey) {
        StringBuilder sb = new StringBuilder();
        sb.append("delete from ").append(tableName).append(" where ");
        // 获取主键字段名
        Map.Entry<String, ColumnData> entry = peKey.entrySet().iterator().next();
        String primaryKeyColumn = entry.getKey();
        // 构造 IN 子句，支持批量删除
        sb.append(primaryKeyColumn).append(" in ");
        sb.append("<foreach collection='pks' item='pk' open='(' separator=',' close=')'>");
        sb.append("#{pk}");
        sb.append("</foreach>");
        return sb.toString();
    }

    private String selectByPk(String tableName, Map<String, ColumnData> peKey) {
        StringBuilder sb = new StringBuilder();
        sb.append("select <include refid=\"Base_Column_List\" /> \n");
        sb.append("\t from ").append(tableName).append(" where ");
        Map.Entry<String, ColumnData> entry = peKey.entrySet().iterator().next();
        sb.append(entry.getKey()).append("= #{").append("pk").append("}");
        return sb.toString();
    }


    private String findByPk(String tableName, Map<String, ColumnData> peKey) {
        StringBuilder sb = new StringBuilder();
        sb.append("select <include refid=\"Base_Column_List\" /> \n");
        sb.append("\t from ").append(tableName).append(" where ");
        Map.Entry<String, ColumnData> entry = peKey.entrySet().iterator().next();
        sb.append(entry.getKey()).append("= #{").append("pk").append("}");
        return sb.toString();
    }

    private String update(String tableName, List<ColumnData> dataList, Map<String, ColumnData> peKey) {
        StringBuilder sets = new StringBuilder("\t<trim  suffixOverrides=\",\" >\n");
        for (ColumnData data : dataList) {
            if (!peKey.containsKey(data.getColumnName())) {
                sets.append("\t<if test=\"").append(data.getPropertyName()).append(" != null ");
                // String 还要判断是否为空
                if ("String" == data.getDataType()) {
                    sets.append(" and ").append(data.getPropertyName()).append(" != ''");
                }
                sets.append(" \">\n\t\t");
                sets.append(data.getColumnName() + "=#{" + data.getPropertyName() + "},\n");
                sets.append("\t</if>\n");
            }
        }
        sets.append("\t</trim>");
        Map.Entry<String, ColumnData> entry = peKey.entrySet().iterator().next();
        String update = "update " + tableName + " set \n" + sets.toString() + " where " + entry.getKey() + "=#{"
                + entry.getValue().getPropertyName() + "}";
        return update;
    }

    private String batchUpdate(String tableName, List<ColumnData> dataList, Map<String, ColumnData> peKey) {
        StringBuilder sb = new StringBuilder();

        // 使用 foreach 遍历 models 列表，生成多个 update 语句
        sb.append("<foreach collection=\"models\" item=\"model\" separator=\";\">");

        // 构建单个 update 语句
        StringBuilder sets = new StringBuilder("\t<trim suffixOverrides=\",\" >\n");
        for (ColumnData data : dataList) {
            if (!peKey.containsKey(data.getColumnName())) {
                sets.append("\t<if test=\"model.").append(data.getPropertyName()).append(" != null ");
                // String 还要判断是否为空
                if ("String".equals(data.getDataType())) {
                    sets.append(" and model.").append(data.getPropertyName()).append(" != ''");
                }
                sets.append(" \">\n\t\t");
                sets.append(data.getColumnName()).append("=").append("#{model.").append(data.getPropertyName()).append("},\n");
                sets.append("\t</if>\n");
            }
        }
        sets.append("\t</trim>");

        // 添加 WHERE 条件，使用主键进行匹配
        Map.Entry<String, ColumnData> entry = peKey.entrySet().iterator().next();
        sb.append("update ").append(tableName).append(" set \n").append(sets.toString())
                .append(" where ").append(entry.getKey()).append("=#{model.").append(entry.getValue().getPropertyName()).append("}");

        sb.append("</foreach>");

        return sb.toString();
    }

    private String insert(String tableName, List<ColumnData> columns, Map<String, ColumnData> peKey) {
        String column = combineColumn(columns, 1, peKey);
        String propertyName = combineColumn(columns, 0, peKey);
        return "insert into " + tableName + "(" + column.replaceAll("\\|", ",") + ")\n values(#{"
                + propertyName.replaceAll("\\|", "},#{") + "})";
    }

    private String batchSave(String tableName, List<ColumnData> columns, Map<String, ColumnData> peKey) {
        String column = combineColumn(columns, 1, peKey);
        StringBuilder sb = new StringBuilder();

        sb.append("insert into ").append(tableName).append(" (").append(column.replaceAll("\\|", ",")).append(")\n");
        sb.append("values\n");
        sb.append("<foreach collection=\"models\" item=\"model\" separator=\",\">");
        sb.append("(");

        String[] propertyNames = combineColumn(columns, 0, peKey).split("\\|");
        for (int i = 0; i < propertyNames.length; i++) {
            if (i > 0) {
                sb.append(",");
            }
            sb.append("#{model.").append(propertyNames[i]).append("}");
        }

        sb.append(")");
        sb.append("</foreach>");

        return sb.toString();
    }
}
